<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>测试代码</title>
  <link rel="shortcut icon" sizes="16x16" href="src/images/favicon_16.ico">
  <link rel="shortcut icon" sizes="32x32" href="src/images/favicon_32.ico">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <script src="https://cdn.bootcss.com/jquery/2.2.0/jquery.min.js"></script>
</head>

<body>
  <style>
    /* 给每个样式前面都加上 #app_transparent_img ，以此避免与其它样式冲突的可能性*/

    #app_transparent_img #toolbar {
      box-sizing: border-box;
    }

    #app_transparent_img #canvas-container {
      position: relative;
    }

    #app_transparent_img #target_canvas {
      background-color: #fff;
      background-image: linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc), linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc);
      background-size: 20px 20px;
      background-position: 0 0, 10px 10px;
      border: 1px solid #ccc;
    }

    #app_transparent_img #toolbar .btn {
      background-color: #8BC34A;
      border: 1px solid #4CAF50;
      border-radius: 4px;
      color: #fff !important;
      cursor: pointer;
      display: inline-block;
      font-size: 16px;
      padding: 4px 8px;
      text-decoration: none;
      height: 20px;
      line-height: 20px;
    }

    #app_transparent_img #toolbar .btn:hover {
      background-color: #4CAF50;
    }

    #app_transparent_img .recover-mode {
      cursor: none;
    }

    #app_transparent_img #recover_img {
      /* 图片的鼠标样式隐藏，防止拖动太快出现鼠标闪烁现象 */
      cursor: none;
      display: none;
      position: absolute;
      /* 这里要加1px是因为我们的target_canvas有个1px的边框 */
      top: 1px;
      left: 1px;
      border: 1px solid #f00;
    }
  </style>
  <div id="app_transparent_img">
    <div id="toolbar">
      <a class="btn" id="btn_select_file" href="jacascript:void(0)">选择背景图</a>
      <input id="target_file" type="file" style="display:none" />
      <a class="btn" id="btn_recover" href="jacascript:void(0)">开启恢复模式</a>
    </div>
    <div id="canvas-container">

    </div>
  </div>
  <script type="text/javascript">
    // 图片背景透明化相关代码
    if ($('#app_transparent_img').length === 1) {
      var recoverSize = 20;
      var transparentConfig = {
        colorDiff: 20,
        setRecoverSize: function (value) {
          recoverSize = value;
          $('#recover_img').css({
            width: value,
            height: value
          })
        }
      };
      (function () {
        var img = new Image();
        var isRecoverMode = false;
        var canvasInfo = {
          width: 0,
          height: 0
        }
        var imgDataArr = []
        var resultImgDataArr = []

        /**
         * 将canvas某块区域设置为透明
         */
        function setTransparent(ctx, x, y, width, height) {
          ctx.putImageData(ctx.createImageData(width, height), x, y);
        }
        /**
         * 设置canvas图像到下载链接上
         */
        function setCanvasImgToDownloadLink() {
          var imgData = document.getElementById('target_canvas').toDataURL();
          $('#download_file').attr('href', imgData);
        };
        /**
         * 获取图像数据中指定偏移处的颜色信息
         */
        function getColorInfo(imgDataArr, offsetX, offsetY) {
          var pos = canvasInfo.width * 4 * offsetY + offsetX * 4;
          return {
            rValue: imgDataArr[pos],
            gValue: imgDataArr[pos + 1],
            bValue: imgDataArr[pos + 2],
            aValue: imgDataArr[pos + 3]
          }
        }
        /**
         * 获取图像数据指定位置颜色与指定颜色的色差
         */
        function getColorDiff(imgDataArr, pos, colorInfo) {
          var value = Math.pow(imgDataArr[pos] - colorInfo.rValue, 2) +
            Math.pow(imgDataArr[pos + 1] - colorInfo.gValue, 2) +
            Math.pow(imgDataArr[pos + 2] - colorInfo.bValue, 2);

          return Math.pow(value, 0.5);
        }
        /**
         * 设置图像数据指定位置为透明色
         */
        function setTransparent(imgDataArr, pos) {
          imgDataArr[pos] = 0;
          imgDataArr[pos + 1] = 0;
          imgDataArr[pos + 2] = 0;
          imgDataArr[pos + 3] = 0;
        }
        /**
         * 非恢复模式下，点击canvas，以点击处颜色为标准，去掉颜色色差在指定色差范围内的颜色
         */
        function transparetModeCanvasClick(e) {
          if (imgDataArr.length === 0) {
            return;
          }
          if (resultImgDataArr.length === 0) {
            resultImgDataArr = imgDataArr.slice(0)
          }
          var clickColorInfo = getColorInfo(resultImgDataArr, e.offsetX, e.offsetY)

          // 如果是透明颜色则不做处理
          if (clickColorInfo.aValue === 0) {
            return;
          }

          var ctx = document.getElementById('target_canvas').getContext('2d');
          for (var pos = canvasInfo.width * canvasInfo.height * 4 - 4; pos >= 0; pos = pos - 4) {
            if (getColorDiff(resultImgDataArr, pos, clickColorInfo) < transparentConfig.colorDiff) {
              setTransparent(resultImgDataArr, pos);
            }
          }
          ctx.putImageData(new ImageData(resultImgDataArr, canvasInfo.width, canvasInfo.height), 0, 0);
          setCanvasImgToDownloadLink();
        }
        // 根据鼠标的偏移位置获取recover_img位置
        function getRecoverImgPos(e) {
          // 给鼠标位置+1，是为了让recover_img不会出现在鼠标下方，从而使得鼠标点击时不会点击在recover_img上
          return {
            x: e.offsetX + 1,
            y: e.offsetY + 1
          }
        }

        var timerHandler = 0
        /**
         * 恢复模式下，鼠标在canvas上移动，呈现原先图像
         */
        function recoverModeCanvasMove(e) {
          if (imgDataArr.length === 0) {
            return;
          }
          var $recoverImg = $("#recover_img");
          var recoverImgPos = getRecoverImgPos(e)
          if (recoverImgPos.x > canvasInfo.width - recoverSize || recoverImgPos.y > canvasInfo.height - recoverSize) {
            $recoverImg.hide();
            return;
          } else {
            $recoverImg.show();
          }
          $recoverImg.css({
            transform: 'translate(' + recoverImgPos.x + 'px,' + recoverImgPos.y + 'px)',
            'background-position': (-recoverImgPos.x - 1) + 'px ' + (-recoverImgPos.y - 1) + 'px'
          });

        }

        /**
         * 恢复模式下，点击canvas，将点击处指定范围内图像恢复原样
         */
        function recoverModeCanvasClick(e) {
          if (imgDataArr.length === 0) {
            return;
          }
          var recoverImgPos = getRecoverImgPos(e);
          for (var i = 0, ylen = recoverSize; i < ylen; i++) {
            var pos = canvasInfo.width * 4 * (recoverImgPos.y + i) + recoverImgPos.x * 4;
            for (var j = pos, xlen = pos + recoverSize * 4; j < xlen; j++) {
              resultImgDataArr[j] = imgDataArr[j]
            }
          }
          var ctx = document.getElementById('target_canvas').getContext('2d');
          ctx.putImageData(new ImageData(resultImgDataArr, canvasInfo.width, canvasInfo.height), 0, 0);
          setCanvasImgToDownloadLink()
        }

        /**
         * 设置Canvas高度和宽度
         * @param {number} width
         * @param {number} height
         */
        function setCanvasSize(width, height) {
          canvasInfo.width = width;
          canvasInfo.height = height;
          $('#target_canvas').attr('width', width).attr('height', height);
          // 解决图片过大时，在canvas-container不能根据canvas的宽度自动撑宽的问题
          $('#app_transparent_img').css({
            width: width < 500 ? 500 : width,
          });
        };
        /**
         * 加载图片资源到canvas中
         * @param {File} imgFile
         */
        function setImgIntoCanvas(imgFile) {
          var reader = new FileReader();

          reader.onloadend = function (e) {
            var dataURL = e.target.result;
            img.onload = function (event) {
              var ctx = document.getElementById('target_canvas').getContext('2d');
              //将canvas大小设置为和图片一样大
              var imgWidth = event.target.naturalWidth,
                imgHeight = event.target.naturalHeight;
              setCanvasSize(imgWidth, imgHeight);
              ctx.drawImage(img, 0, 0);

              imgDataArr = ctx.getImageData(0, 0, imgWidth, imgHeight).data;
              resultImgDataArr = imgDataArr.slice(0)
              setCanvasImgToDownloadLink();
            };
            img.src = dataURL;
            $('#recover_img').css("background-image", "url(" + dataURL + ")");
          };
          reader.readAsDataURL(imgFile);
        }

        // 绑定事件
        var bindEvent = function () {
          // 按下选择的背景图
          $('#btn_select_file').click(function () {
            $('#target_file').click();
          });
          // 文件改变时获取文件，并文件渲染进canvas
          $('#target_file').change(function (event) {
            var imgFile = event.target.files[0];
            setImgIntoCanvas(imgFile);
          });
          // 开启恢复模式
          $('#btn_recover').click(function () {
            var $targetCanvas = $('#target_canvas');
            $targetCanvas.off("click").off("mousemove").removeClass('recover-mode');

            isRecoverMode = !isRecoverMode
            if (isRecoverMode) {
              $("#recover_img").css({
                width: recoverSize,
                height: recoverSize
              });
              $targetCanvas.addClass('recover-mode').click(recoverModeCanvasClick).mousemove(recoverModeCanvasMove).mouseleave(function () {
                $("#recover_img").hide();
              });
              $('#btn_recover').text('关闭恢复模式')
            } else {
              $targetCanvas.click(transparetModeCanvasClick);
              $("#recover_img").hide();
              $('#btn_recover').text('开启恢复模式')
            }
          })
        };


        // 此处通过这种方式将html插入，是因为博客园自动屏蔽了canvas标签和download属性
        var initHtmlConstruct = function () {
          var $container = $('#canvas-container');
          // 加入处理图片的canvas
          $container.text('').append('<canvas id="target_canvas" width="100" height="100">浏览器不支持此功能，请升级</canvas>')
          // 处理recover模式下的跟随鼠标的图像
          $container.append('<div id="recover_img"></div>')
          $('#toolbar').append('<a class="btn" id="download_file" href="#" download="透明化图片">下载合成图片</a>');
        }
        // 初始化canvas信息
        var initCanvasInfo = function () {
          var $targetCanvas = $('#target_canvas');
          if ($targetCanvas.length === 1) {
            var canvasPosition = $targetCanvas.offset()
            canvasInfo.width = $targetCanvas.width();
            canvasInfo.height = $targetCanvas.height();
          }
          //点击canvas，以点击处颜色为标准，去掉颜色色差在指定色差范围内的颜色
          $targetCanvas.off("click").click(transparetModeCanvasClick)
        }
        $(function () {
          if ($('#app_transparent_img').length === 1) {
            initHtmlConstruct();
            initCanvasInfo();
            bindEvent();
            $(window).resize(function () {
              // 窗口大小调整后canvas位置发生改变
              initCanvasInfo();
            });
          }
        })
      })();
    }
  </script>
</body>

</html>
